package cn.snmp.mutual.uk.stack;

import lombok.extern.slf4j.Slf4j;
import cn.snmp.mutual.uk.beans.UsmBeingDiscoveredBean;
import cn.snmp.mutual.uk.event.RequestPduListener;

import java.io.*;

@Slf4j
public class SnmpContextv3 extends SnmpContextv3Basis {
    private static final String version_id = "@(#)$Id: SnmpContextv3.java,v 3.31 2009/03/05 13:12:50 birgita Exp $ Copyright Westhawk Ltd";
    private UsmBeingDiscoveredBean myDiscBean;

    public SnmpContextv3(final String host, final int port) throws IOException {
        super(host, port);
        this.myDiscBean = null;
    }

    public SnmpContextv3(final String host, final int port, final String typeSocketA) throws IOException {
        super(host, port, typeSocketA);
        this.myDiscBean = null;
    }

    public SnmpContextv3(final String host, final int port, final String bindAddress, final String typeSocketA) throws IOException {
        super(host, port, bindAddress, typeSocketA);
        this.myDiscBean = null;
    }

    @Override
    public void addRequestPduListener(final RequestPduListener l, final ListeningContextPool lcontext) throws IOException {
        super.addRequestPduListener(l, lcontext);
        if (this.myDiscBean == null) {
            this.myDiscBean = new UsmBeingDiscoveredBean(this, this.usmAgent);
        }
        this.myDiscBean.addRequestPduListener(lcontext);
    }

    @Override
    public void removeRequestPduListener(final RequestPduListener l, final ListeningContextPool lcontext) throws IOException {
        super.removeRequestPduListener(l, lcontext);
        if (this.myDiscBean != null) {
            this.myDiscBean.removeRequestPduListener(lcontext);
            this.myDiscBean.freeResources();
            this.myDiscBean = null;
        }
    }

    @Override
    public Pdu processIncomingPdu(final byte[] message) throws DecodingException, IOException {
        final String msg = this.checkContextSanity();
        if (msg != null) {
            throw new DecodingException(msg);
        }
        final int l = message.length;
        final byte[] copyOfMessage1 = new byte[l];
        final byte[] copyOfMessage2 = new byte[l];
        System.arraycopy(message, 0, copyOfMessage1, 0, l);
        System.arraycopy(message, 0, copyOfMessage2, 0, l);
        final AsnDecoderv3 rpdu = new AsnDecoderv3();
        final ByteArrayInputStream in = new ByteArrayInputStream(message);
        final AsnSequence asnTopSeq = rpdu.DecodeSNMPv3(in);
        final int msgId = rpdu.getMsgId(asnTopSeq);
        Pdu pdu = null;
        DecodingException encryptionDecodingException1 = null;
        IOException encryptionIOException1 = null;
        try {
            pdu = this.processPotentialTrap(rpdu, asnTopSeq, copyOfMessage1);
        } catch (DecodingException exc) {
            encryptionDecodingException1 = exc;
            if (AsnObject.debug > 3) {
                System.out.println(this.getClass().getName() + ".processPotentialTrap(): DecodingException: " + exc.getMessage());
            }
            log.error(".processPotentialTrap(): DecodingException: " + exc.getMessage());
        } catch (IOException exc2) {
            encryptionIOException1 = exc2;
            if (AsnObject.debug > 3) {
                System.out.println(this.getClass().getName() + ".processPotentialTrap(): IOException: " + exc2.getMessage());
            }
        }
        DecodingException encryptionDecodingException2 = null;
        IOException encryptionIOException2 = null;
        if (pdu == null) {
            try {
                pdu = this.processPotentialRequest(rpdu, asnTopSeq, copyOfMessage2);
            } catch (DecodingException exc3) {
                encryptionDecodingException2 = exc3;
                if (AsnObject.debug > 3) {
                    System.out.println(this.getClass().getName() + ".processPotentialRequest(): DecodingException: " + exc3.getMessage());
                }
            } catch (IOException exc4) {
                encryptionIOException2 = exc4;
                if (AsnObject.debug > 3) {
                    System.out.println(this.getClass().getName() + ".processPotentialRequest(): IOException: " + exc4.getMessage());
                }
            }
        }
        if (pdu != null) {
            pdu.snmpv3MsgId = new Integer(msgId);
        } else {
            if (encryptionIOException2 != null) {
                throw encryptionIOException2;
            }
            if (encryptionDecodingException2 != null) {
                throw encryptionDecodingException2;
            }
            if (encryptionIOException1 != null) {
                throw encryptionIOException1;
            }
            if (encryptionDecodingException1 != null) {
                throw encryptionDecodingException1;
            }
        }
        return pdu;
    }

    public Pdu processPotentialTrap(final AsnDecoderv3 rpdu, final AsnSequence asnTopSeq, final byte[] message) throws DecodingException, IOException {
        final AsnPduSequence pduSeq = rpdu.processSNMPv3(this, asnTopSeq, message, false);
        Pdu pdu = null;
        if (pduSeq != null) {
            final byte type = pduSeq.getRespType();
            if (type == -89) {
                pdu = new TrapPduv2(this);
                pdu.fillin(pduSeq);
                if (AsnObject.debug > 3) {
                    System.out.println(this.getClass().getName() + ".processPotentialTrap(): PDU received with type " + pduSeq.getRespTypeString() + ". Not ignoring it!");
                }
            } else if (AsnObject.debug > 3) {
                System.out.println(this.getClass().getName() + ".processPotentialTrap(): PDU received is not TRPV2_REQ_MSG" + ". Ignoring it.");
            }
        } else if (AsnObject.debug > 3) {
            System.out.println(this.getClass().getName() + ".processPotentialTrap(): pduSeq == null" + ". Ignoring it.");
        }
        return pdu;
    }

    public Pdu processPotentialRequest(final AsnDecoderv3 rpdu, final AsnSequence asnTopSeq, final byte[] message) throws DecodingException, IOException {
        final AsnPduSequence pduSeq = rpdu.processSNMPv3(this, asnTopSeq, message, true);
        Pdu pdu = null;
        if (pduSeq != null) {
            final byte type = pduSeq.getRespType();
            if (type == -96 && pduSeq.isSnmpv3Discovery()) {
                if (AsnObject.debug > 3) {
                    System.out.println(this.getClass().getName() + ".ProcessIncomingPdu(): received discovery pdu" + ". Ignoring it.");
                }
            } else {
                switch (type) {
                    case -96: {
                        pdu = new GetPdu(this);
                        pdu.fillin(pduSeq);
                        break;
                    }
                    case -95: {
                        pdu = new GetNextPdu(this);
                        pdu.fillin(pduSeq);
                        break;
                    }
                    case -93: {
                        pdu = new SetPdu(this);
                        pdu.fillin(pduSeq);
                        break;
                    }
                    case -91: {
                        pdu = new GetBulkPdu(this);
                        pdu.fillin(pduSeq);
                        break;
                    }
                    case -90: {
                        pdu = new InformPdu(this);
                        pdu.fillin(pduSeq);
                        break;
                    }
                    default: {
                        if (AsnObject.debug > 3) {
                            System.out.println(this.getClass().getName() + ".processPotentialRequest(): PDU received with type " + pduSeq.getRespTypeString() + ". Ignoring it.");
                            break;
                        }
                        break;
                    }
                }
                if (pdu != null && AsnObject.debug > 3) {
                    System.out.println(this.getClass().getName() + ".processPotentialRequest(): PDU received with type " + pduSeq.getRespTypeString() + ". Not ignoring it!");
                }
            }
        } else if (AsnObject.debug > 3) {
            System.out.println(this.getClass().getName() + "..processPotentialRequest(): pduSeq == null" + ". Ignoring it.");
        }
        return pdu;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        SnmpContextv3 clContext = null;
        try {
            clContext = new SnmpContextv3(this.hostname, this.hostPort, this.bindAddr, this.typeSocket);
            clContext = (SnmpContextv3) this.cloneParameters(clContext);
        } catch (IOException exc) {
            throw new CloneNotSupportedException("IOException " + exc.getMessage());
        }
        return clContext;
    }
}
